<script setup>
import {constantStore} from "@/stores/constantStore.js";
import {onMounted, ref, watch} from "vue";
import MyTag from "@/components/constant/myTag.vue";
import MySwitch from "@/components/constant/mySwitch.vue";
import MySelect from "@/components/constant/mySelect.vue";
import MyImage from "@/components/image/myImage.vue";
import {successCode} from "@/api/httpApi/base/http.js";
import {error, success, warning} from "@/api/myMessage.js";
import MySelectText from "@/components/constant/mySelectText.vue";

/***********************************组件部分********************************/
const props = defineProps({
  dataList: {
    type: Array,
    default: null
  },
  mapping: {
    type: Array,
    default: [
      {
        label: "",//表头名称 必填
        prop: "",//数据对应字段 必填
        propConfig: {
          align: "left",//center left right 对齐方式 非必填 不写默认左对齐
          width: "100",//宽度 非必填 不写默认撑开
          type: "text",// 非必填 不写默认text   text(文本) selectText(根据给定列表，选择内容)  tag(标签)  Switch(开关)  image(图片)
          fixed: 'left',//固定列的位置
        },
        editHandle: "add_update",//出现在编辑中的操作 必填  添加有  修改有，
        editTypeConfig: {
          editProp: "",// 编辑框的数据字段名称  非必填 不写默认用prop
          labelWidth: "100",//表单label宽度 非必填 不写默认100
          required: true,//是否必传，默认false
          rules: [],//构建默认的参数校验规则
          editType: "text", //编辑框类型，非必填 默认text 文本类型  支持图片类型（image） 选择框（select），
          editTextType: "text"//文本框类型， text number等，和input一样
        }
      },
      {
        label: "",
        prop: "",
        propConfig: {
          align: "center",
          width: "100",
          type: "text"
        },
        editHandle: "add_update",//出现在编辑中的操作 必填  添加有  修改有，
        editTypeConfig: {
          editProp: "",// 编辑框的数据字段名称  非必填 不写默认用prop
          labelWidth: "",
          editType: "select", //编辑框类型，非必填 默认text 文本类型  支持图片类型（image） 选择框（select），
          required: true,//是否必传，默认false
          option: [//选择框内数据
            {
              label: '',
              value: ''
            }
          ]
        }
      },
    ]
  },
  editObject: {
    type: Object,
    default: null
  },
  title: {
    type: String,
    default: ""
  },
  hasPage: {
    type: Boolean,
    default: false
  },
  btnConfig: {
    default: {
      add: true,
      update: true,
      del: true
    }
  },
  initAction: {
    type: Function,
    default: null
  },
  addAction: {
    type: Function,
    default: null
  },
  updateAction: {
    type: Function,
    default: null
  },
  editAction: {
    type: Function,
    default: null
  },
  delAction: {
    type: Function,
    default: null
  },
  editBtnWidth: {
    type: Number,
    default: 160,
    required: false,
  },
  canSelect: {
    type: Boolean,
    default: false,
    required: false,
  }
})

const emits = defineEmits(["afterEdit", "selectChange"]);
// 可以直接侦听一个 ref
watch(() => props.dataList, async (newQuestion) => {
  tableDataList.value = newQuestion;
  initLoading.value = false;
})

function itemIsNull(item) {
  return item === '' || item === null || item === undefined
}

/***********************************初始化部分********************************/
let tableDataList = ref([]);
let initLoading = ref(true);
onMounted(() => {
  initData();
  initEditForm();
  initRules();
})

function initList() {
  if (props.initAction != null) {
    initLoading.value = true;
    props.initAction(props.hasPage ? pageObj : "").then(res => {
      initLoading.value = false;
      if (res.code === successCode) {
        if (props.hasPage) {
          setResData(res.data)
        } else {
          if (!itemIsNull(res.data) && !itemIsNull(res.data.content)) {
            tableDataList.value = res.data.content;
          } else {
            tableDataList.value = res.data;
          }
        }
      }
    })
  }
}

function initData() {
  if (props.dataList != null && props.dataList.length > 0) {
    tableDataList.value = props.dataList;
    initLoading.value = false;
  } else {
    initList();
  }
}

function initEditForm() {
  if (props.editObject != null) {
    editForm.value = props.editObject;
  } else {
    props.mapping.forEach(item => {
      if (!itemIsNull(item.editTypeConfig) && !itemIsNull(item.editTypeConfig.editProp)) {
        editForm.value[item.editTypeConfig.editProp] = "";
      } else {
        editForm.value[item.prop] = "";
      }
    })
  }

}

//初始化校验规则
const rules = ref({})

function initRules() {
  for (let i = 0; i < props.mapping.length; i++) {
    let item = props.mapping[i];

    let rulesItemArr = [];

    //构建非空校验
    if (!itemIsNull(item.editTypeConfig) && !itemIsNull(item.editTypeConfig.required)) {
      let msg = "不能为空，请";
      let trigger = "blur";
      if (item.editTypeConfig.editType === "select") {
        msg += "选择"
        trigger = "change";
      } else if (item.editTypeConfig.editType === "image") {
        msg += "上传"
        trigger = "change";
      } else {
        msg += "输入"
        trigger = "blur";
      }
      rulesItemArr.push({
        required: item.editTypeConfig.required,
        message: item.label + msg + "后重试",
        trigger: trigger
      });
    }

    //构建自定义校验
    if (!itemIsNull(item.editTypeConfig) && !itemIsNull(item.editTypeConfig.rules)) {
      rulesItemArr.concat(item.editTypeConfig.rules)
    }

    //封装规则
    if (rulesItemArr.length > 0) {
      if (!itemIsNull(item.editTypeConfig) && !itemIsNull(item.editTypeConfig.editProp)) {
        rules.value[item.editTypeConfig.editProp] = rulesItemArr;
      } else {
        rules.value[item.prop] = rulesItemArr;
      }
    }

  }
}

/***********************************编辑部分********************************/
let editDialogShow = ref(false);
let editBtnMsg = ref("");//编辑框的按钮内容
let editDialogTitleMsg = ref("");//编辑框的按钮内容
let editBtnLoading = ref(false);//编辑框确定按钮的加载

let editForm = ref({});
let isAdd = ref(false);

function addBefore() {
  isAdd.value = true;
  editBtnMsg.value = "添 加"
  editDialogTitleMsg.value = "添加" + props.title
  clearEditObject();
  editDialogShow.value = true;
}

let updateItemIndex = ref(-1);

function hasEditProp(item) {
  return !itemIsNull(item.editTypeConfig) && !itemIsNull(item.editTypeConfig.editProp);
}

function updateBefore(itemIndex, updateItem) {
  isAdd.value = false;
  editBtnMsg.value = "修 改"
  editDialogTitleMsg.value = "修改" + props.title
  props.mapping.forEach((item) => {
    if (hasEditProp(item)) {
      editForm.value[item.editTypeConfig.editProp] = updateItem[item.editTypeConfig.editProp];
    } else {
      editForm.value[item.prop] = updateItem[item.prop];
    }
  })
  updateItemIndex.value = itemIndex;
  editDialogShow.value = true;
}

function clearEditObject() {
  props.mapping.forEach((item) => {
    if (hasEditProp(item)) {
      editForm.value[item.editTypeConfig.editProp] = "";
    } else {
      editForm.value[item.prop] = "";
    }
  })
}

const formRef = ref();

async function doEdit(formEl) {
  if (!formEl) {
    return
  }
  await formEl.validate((valid, fields) => {
    if (!valid) {
      // for (let key in fields) {
      //   warning(fields[key].message);
      return false;
      // }
    }
  })
  editBtnLoading.value = true;
  if (props.editAction === null) {
    if (isAdd.value) {
      props.addAction(editForm.value).then(res => {
        if (res.code === successCode) {
          doEditAfter(res);
        } else {
          error(res.message);
        }
        editBtnLoading.value = false;
      })
    } else {
      props.updateAction(editForm.value).then(res => {
        if (res.code === successCode) {
          doEditAfter(res);
        } else {
          error(res.message);
        }
        editBtnLoading.value = false;
      })
    }
  } else {
    props.editAction(editForm.value).then(res => {
      if (res.code === successCode) {
        doEditAfter(res);
      } else {
        error(res.message);
      }
      editBtnLoading.value = false;
    })
  }
}


function doEditAfter(res) {
  clearEditObject();
  initList()
  emits("afterEdit");
  success(res.message);
  editDialogShow.value = false;
}

/***********************************删除部分********************************/
let delDialogShow = ref(false);
let delBtnLoading = ref(false);
let delBtnDisabled = ref(false);
let ids = ref([]);
let delTips = ref("");

function delCancel() {
  editDialogShow.value = false;
  ids.value = [];
  delTips.value = ""
}

function delBefore(delItemIndex, delItem) {
  delBtnDisabled.value = false;
  ids.value = [];
  delDialogShow.value = true;
  ids.value.push(delItem.id);
  delTips.value = "您确定要删除 <span style='color: #f13468'>“" + delItem.name + "”</span> 吗？";
}

function doDelete() {
  delBtnLoading.value = true;
  props.delAction(ids.value).then(res => {
    if (res.code === successCode) {
      delAfter(res);
    } else {
      error(res.message);
    }
  })
  delBtnLoading.value = false;
}

function delAfter(res) {
  initList()
  success(res.message);
  ids.value = [];
  delTips.value = "";
  delDialogShow.value = false;
  delBtnDisabled.value = false;
  emits("afterEdit");
}

function delArrBefore() {
  if (ids.value.length === 0) {
    delTips.value = " 请选择要删除的内容 ";
    delBtnDisabled.value = true;
  }
  delDialogShow.value = true;
}

/***********************************多选部分********************************/
function selectionChange(arr) {
  delBtnDisabled.value = false;
  ids.value = [];
  let nameStr = "";
  arr.forEach(item => {
    ids.value.push(item.id);
    nameStr += item.name + "，";
  })
  emits("selectChange", arr)
  delTips.value = "您确定要删除 <span style='color: #f13468'>“" + nameStr.substring(0, nameStr.length - 1) + "”</span> 吗？";
}

/***********************************页码部分********************************/
let pageObj = ref({
  currentPage: 1,
  pageSize: 10,
  totalPages: 10,
  totalCount: 100,
  first: false,
  last: false,
})
const handleSizeChange = (val) => {
  pageObj.value.pageSize = val;
}
const handleCurrentChange = (val) => {
  pageObj.value.currentPage = val;
  props.initAction(pageObj).then(res => {
    if (res.code === successCode) {
      setResData(res.data)
    }
    initLoading.value = false;
  })
}

function setResData(resData) {
  if (!constantStore().itemIsNull(resData.page)) {
    pageObj.value.currentPage = resData.page;
    pageObj.value.pageSize = resData.size;
    pageObj.value.totalCount = resData.totalCount;
    pageObj.value.totalPages = resData.totalPages;
    pageObj.value.first = resData.first;
    pageObj.value.last = resData.last;
    tableDataList.value = resData.content;
  } else {
    tableDataList.value = resData;
  }
}

const bigImageShow = ref(false);
const bigImageUrl = ref('');
const naturalSize = ref('');

function bigImage(imageUrl) {
  bigImageUrl.value = imageUrl;
  // 获取图片的自然宽度和高度
  const img = document.querySelector('.table-image img');
  naturalSize.value = "width:" + ((img.naturalWidth + 20)) + "px;height:" + (img.naturalHeight + 20) + "px;display: flex;align-items: center;justify-content: center;user-select: none;background-color:rgba(255, 255, 255, 0);";
  bigImageShow.value = true;
}

//按钮在添加时候只需要一个 <div class="button-box-item"></div>包裹，就可以同步CSS效果
</script>

<template>
  <div class="my-table-box" :style="canSelect?'':'user-select: none'">
    <div class="button-box" v-if="!(!btnConfig.add&&!btnConfig.del&&!$slots.buttonAdd)">
      <div class="button-box-item" v-if="btnConfig.add">
        <el-button type="primary" @click="addBefore">添 加</el-button>
      </div>
      <div class="button-box-item" v-if="btnConfig.del">
        <el-button type="danger" @click="delArrBefore">批量删除</el-button>
      </div>
      <slot name="buttonAdd"></slot>
    </div>
    <div class="table-box" v-loading="initLoading">
      <el-table :data="tableDataList" style="width: 100%"
                @selection-change="selectionChange"
                border highlight-current-row stripe lazy fit>
        <el-table-column :type="btnConfig.del?'selection':''" width="55"/>
        <template v-for="(item,index) in mapping">
          <template v-if="item.propConfig.type==='tag'">
            <el-table-column :align="item.propConfig.align ===null?'left':item.propConfig.align"
                             :label="item.label" :fixed="itemIsNull(item.propConfig.fixed)?false:item.propConfig.fixed"
                             :width="item.propConfig.width ===null?'':item.propConfig.width">
              <template #default="scope">
                <my-tag :data="scope.row[item.prop]" :mapping="item.propConfig.stateMapping"/>
              </template>
            </el-table-column>
          </template>
          <template v-else-if="item.propConfig.type==='switch'">
            <el-table-column :align="item.propConfig.align ===null?'left':item.propConfig.align"
                             :label="item.label"
                             :fixed="itemIsNull(item.propConfig.fixed)?false:item.propConfig.fixed"
                             :width="item.propConfig.width ===null?'':item.propConfig.width">
              <template #default="scope">
                <my-switch :switch="scope.row[item.prop]" :model-action="item.propConfig.modelAction"
                           :true-action="item.propConfig.trueAction" :false-action="item.propConfig.falseAction"/>
              </template>
            </el-table-column>
          </template>
          <template v-else-if="item.propConfig.type==='image'">
            <el-table-column :align="item.propConfig.align ===null?'left':item.propConfig.align"
                             :label="item.label"
                             :fixed="itemIsNull(item.propConfig.fixed)?false:item.propConfig.fixed"
                             :width="item.propConfig.width ===null?'':item.propConfig.width">
              <template #default="scope">
                <el-image class="table-image" @click="bigImage(scope.row[item.prop])" :src="scope.row[item.prop]"
                          style="max-width: 5rem;max-height: 8rem"/>
              </template>
            </el-table-column>
          </template>
          <template v-else-if="item.propConfig.type==='selectText'">
            <el-table-column :align="item.propConfig.align ===null?'left':item.propConfig.align"
                             :label="item.label"
                             :fixed="itemIsNull(item.propConfig.fixed)?false:item.propConfig.fixed"
                             :width="item.propConfig.width ===null?'':item.propConfig.width">
              <template #default="scope">
                {{ scope.row[item.prop] }}
                <my-select-text :data="scope.row[item.prop]" :mapping="item.propConfig.option"/>
              </template>
            </el-table-column>
          </template>
          <template v-else>
            <el-table-column :align="item.propConfig.align ===null?'left':item.propConfig.align"
                             :prop="item.prop"
                             :fixed="itemIsNull(item.propConfig.fixed)?false:item.propConfig.fixed"
                             :label="item.label"
                             :width="item.propConfig.width ===null?'':item.propConfig.width"/>
          </template>
        </template>
        <el-table-column v-if="!(!btnConfig.update&&!btnConfig.del&&!$slots.tableBtnCover)"
                         align="center" label="操 作" :width="props.editBtnWidth" fixed="right">
          <template #default="scope">
            <template v-if="$slots.tableBtnCover">
              <slot name="tableBtnCover" :row="scope.row" :index="scope.$index"></slot>
            </template>
            <template v-else>
              <el-button v-if="btnConfig.update" size="small" type="primary"
                         @click="updateBefore(scope.$index ,scope.row)">
                编 辑
              </el-button>
              <slot name="tableBtnAdd" :row="scope.row" :index="scope.$index"/>
              <el-button v-if="btnConfig.del" size="small" type="danger" @click="delBefore(scope.$index, scope.row)">
                删 除
              </el-button>
            </template>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <div class="page-box" v-if="hasPage">
      <template v-if="$slots.buttonAdd">
        <slot name="page"></slot>
      </template>
      <template v-else>
        <el-pagination
            v-model:current-page="pageObj.currentPage"
            v-model:page-size="pageObj.pageSize"
            :page-sizes="[10, 20, 50, 100]"
            :small="false"
            :disabled="false"
            :background="false"
            layout="total, sizes, prev, pager, next, jumper"
            :total="pageObj.totalCount"
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"/>
      </template>
    </div>
    <div class="dialog-box">
      <div class="edit-dialog">
        <el-dialog v-model="editDialogShow" :title="editDialogTitleMsg" width="500">
          <el-form ref="formRef" status-icon
                   :model="editForm" :rules="rules">
            <template v-for="(item,index) in mapping">
              <template v-if="!itemIsNull(item.editHandle)&&
                                  ((item.editHandle.includes('add')&&isAdd)||
                                  (item.editHandle.includes('update')&&!isAdd))">
                <el-form-item :label="item.label"
                              :prop="itemIsNull(item.editTypeConfig.editProp)?item.prop:item.editTypeConfig.editProp"
                              :label-width="itemIsNull(item.editTypeConfig.labelWidth)?'100':item.editTypeConfig.labelWidth">
                  <template v-if="itemIsNull(item.editTypeConfig.editProp)">

                    <template v-if="item.editTypeConfig.editType==='select'">
                      <my-select :select-model="editForm[item.prop]"
                                 @change-value="(args) => {
                                   editForm[item.prop]=args;
                                   item.editTypeConfig.change === undefined?'':item.editTypeConfig.change(args);
                                 }"
                                 :placeholder="'请选择'+item.label" :option="item.editTypeConfig.option"/>
                    </template>

                    <template v-else-if="item.editTypeConfig.editType==='image'">
                      <my-image v-model="editForm[item.prop]"
                                :image-config="item.editTypeConfig.imageConfig"
                                :title="'上传'+item.label"
                                :cropper-config="item.editTypeConfig.cropperConfig"/>
                    </template>

                    <template v-else>
                      <el-input v-model="editForm[item.prop]" :type="item.editTypeConfig.editTextType"
                                autocomplete="off" clearable/>
                    </template>

                  </template>
                  <template v-else>

                    <template v-if="item.editTypeConfig.editType==='select'">
                      <my-select :select-model="editForm[item.editTypeConfig.editProp]"
                                 @change-value="(args) => {
                                   editForm[item.editTypeConfig.editProp]=args;
                                   item.editTypeConfig.change === undefined ? '' :item.editTypeConfig.change(args);
                                 }"
                                 :placeholder="'请选择'+item.label" :option="item.editTypeConfig.option"/>
                    </template>

                    <template v-else-if="item.editTypeConfig.editType==='image'">
                      <my-image
                          :modelValue="editForm[item.editTypeConfig.editProp]"
                          :image-config="item.editTypeConfig.imageConfig"
                          :title="'上传'+item.label"
                          :cropper-config="item.editTypeConfig.cropperConfig"/>
                    </template>

                    <template v-else>
                      <el-input v-model="editForm[item.editTypeConfig.editProp]"
                                :type="item.editTypeConfig.editTextType" autocomplete="off" clearable/>
                    </template>

                  </template>
                </el-form-item>
              </template>
            </template>
          </el-form>
          <template #footer>
            <div class="dialog-footer">
              <el-button @click="delCancel">取 消</el-button>
              <el-button type="primary" @click="doEdit(formRef)" :loading="editBtnLoading">
                {{ editBtnMsg }}
              </el-button>
            </div>
          </template>
        </el-dialog>
      </div>
      <div class="del-dialog">
        <el-dialog v-model="delDialogShow" title="删除提醒" width="500">
          <div class="del-tip" v-html="delTips">
          </div>
          <template #footer>
            <div class="dialog-footer">
              <el-button @click="delDialogShow = false">取 消</el-button>
              <el-button type="danger" @click="doDelete" :disabled="delBtnDisabled" :loading="delBtnLoading">
                删 除
              </el-button>
            </div>
          </template>
        </el-dialog>
      </div>
      <div class="big-image-dialog">
        <el-dialog v-model="bigImageShow" :style="naturalSize" :show-close="false" :draggable="true">
          <el-image :src="bigImageUrl"/>
        </el-dialog>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
.my-table-box {
  display: flex;
  flex-direction: column;
  justify-content: space-between;

  .el-form {
    .el-form-item {
      align-items: center !important;

      :deep(.el-form-item__label) {
        user-select: none;
      }
    }
  }

  .button-box {
    display: flex;
    align-items: center;
    flex-wrap: wrap; /* 允许换行 */
    justify-content: start;
    padding: 2rem 1rem;
    border-bottom: #CDD0D6 dashed .2rem;

    :deep(.button-box-item) {
      margin: 1rem;
    }
  }

  .table-box {
    padding: 1rem 1rem;

    .btn-edit-box {
      display: flex;
      align-items: center;
    }

    .btn-add {
      margin: 0 .5rem;
    }
  }

  .page-box {
    padding: 1rem 1rem;
  }

  .dialog-box {
    padding: 2rem 1rem;
  }
}
</style>
